from flask import Blueprint
from flask_login import login_required

from apps.a_common.db import db_flush_all, safe_commit, db_flush
from apps.a_common.log import MyLogger
from apps.a_common.permission import has_permission_decorate
from apps.a_common.request import assert_params_by_form
from apps.a_common.response import paginate_response, success_response, excel_response
from apps.projects.forms import ProjectSearchForm, ProjectEditorForm
from apps.projects.helper import search_project_by_form, generate_project_excel
from apps.projects.models import Project, ProjectUser
from apps.projects.serializers import serialize_project_base_info, serialize_project_all_info

project_blueprint = Blueprint('project', __name__)
log = MyLogger('project views')


@project_blueprint.route('/projects/<int:project_id>/', methods=['GET'])
@login_required
@has_permission_decorate('admin-project-view')
def _get_project(project_id):
    """
    查看一个项目的详情
    ---
    tags:
      - project
    parameters:
      - name: project_id
        in : path
        type: integer
        required: true
        description: 项目的id
    """
    return success_response(serialize_project_all_info(Project.query.filter(Project.id == project_id).first_or_404()))


@project_blueprint.route('/projects/', methods=['GET'])
@login_required
@has_permission_decorate('admin-project-view')
def _get_projects():
    """
    获取项目列表
    ---
    tags:
      - project
    parameters:
      - name: user_id
        in : query
        type: integer
        required: false
        description: 根据user id找项目
      - name: status
        in : query
        type: integer
        required: false
        description: 查找状态
      - name: page_id
        in : query
        type: integer
        required: false
        default: 1
        description: 页码
      - name: page_size
        in : query
        type: integer
        required: false
        default: 20
        description: 每页的大小

    """
    form = assert_params_by_form(ProjectSearchForm)
    queryset = search_project_by_form(form)
    return paginate_response(queryset, serialize_project_base_info)


@project_blueprint.route('/projects/', methods=['POST'])
@login_required
@has_permission_decorate('admin-project-create')
def _post_projects():
    """
    新建项目
    ---
    tags:
      - project
    parameters:
      - name: user_ids
        in : formData
        type: array
        required: false
        description: 参与这个项目的个人
      - name: name
        in : formData
        type: string
        required: true
        description: 项目的名称
      - name: backend
        in : formData
        type: string
        required: false
        description: 项目的背景
      - name: start_at
        in : formData
        type: integer
        required: false
        description: 项目的开始时间
      - name: end_at
        in : formData
        type: integer
        required: false
        description: 项目的结束时间
      - name: need_skills
        in : formData
        type: array
        required: false
        description: 项目所需要的技术
    """
    form = assert_params_by_form(ProjectEditorForm)
    project = Project()

    user_ids = form.pop('user_ids') if form.get('user_ids') else []
    for key, value in form.items():
        setattr(project, key, value)
    db_flush(project)

    project_users = [ProjectUser(user_id=i, project_id=project.id) for i in user_ids]
    db_flush_all(*project_users)

    safe_commit()
    return success_response(serialize_project_base_info(project))


@project_blueprint.route('/projects/<int:project_id>/', methods=['PUT'])
@login_required
@has_permission_decorate('admin-project-change')
def _put_projects(project_id):
    """
    修改项目信息
    ---
    tags:
      - project
    parameters:
      - name: project_id
        in : path
        type: integer
        required: true
        description: 项目的id
      - name: user_ids
        in : formData
        type: array
        required: false
        description: 参与这个项目的个人
      - name: name
        in : formData
        type: string
        required: true
        description: 项目的名称
      - name: backend
        in : formData
        type: string
        required: false
        description: 项目的背景
      - name: start_at
        in : formData
        type: integer
        required: false
        description: 项目的开始时间
      - name: end_at
        in : formData
        type: integer
        required: false
        description: 项目的结束时间
      - name: need_skills
        in : formData
        type: array
        required: false
        description: 项目所需要的技术
      - name: status
        in : formData
        type: integer
        required: false
        description: 项目的状态
    """
    form = assert_params_by_form(ProjectEditorForm)
    project = Project.query.filter(Project.id == project_id).first_or_404()

    user_ids = set(form.pop('user_ids')) if form.get('user_ids') else set()
    project_user_ids = set(
        i[0] for i in ProjectUser.query.filter(ProjectUser.project_id == project_id).values(ProjectUser.user_id))

    for key, value in form.items():
        setattr(project, key, value)

    to_delete_user_ids = project_user_ids - user_ids
    to_add_user_ids = user_ids - project_user_ids
    ProjectUser.query.filter(ProjectUser.project_id == project_id, ProjectUser.user_id.in_(to_delete_user_ids)).delete(
        False)
    db_flush_all(*(ProjectUser(user_id=i, project_id=project.id) for i in to_add_user_ids))

    safe_commit()
    return success_response(serialize_project_base_info(project))


@project_blueprint.route('/projects/download/', methods=['GET'])
@login_required
def _download_projects():
    """
    下载项目
    ---
    tags:
      - project
    parameters:
      - name: user_id
        in : query
        type: integer
        required: false
        description: 根据user id找项目
      - name: status
        in : query
        type: integer
        required: false
        description: 查找状态
    """
    form = assert_params_by_form(ProjectSearchForm)
    queryset = search_project_by_form(form)

    wb = generate_project_excel(queryset.all())
    return excel_response(wb, 'project_list.xlsx')
